// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use core::file::get_current_watch_path;
use std::collections::HashSet;
use std::path::Path;
use std::sync::Arc;

use futures::{SinkExt, StreamExt};
use notify::{Event, RecursiveMode, Watcher};
use serde_json::json;
use tokio::sync::broadcast;
use tokio::{net::TcpListener, sync::Mutex};
use tokio_tungstenite::{accept_async, tungstenite::Message};

pub mod core {
    pub mod file;
    pub mod system;
}

#[tokio::main]
async fn main() {
    // Create a broadcast channel
    let (tx, _) = broadcast::channel::<String>(16);

    // Set the WebSocket sender for real-time scan updates
    core::file::set_websocket_sender(tx.clone());

    start_watch_folder(tx.clone());
    // Bind the server to a local address
    let addr = "127.0.0.1:3030";
    let listener = TcpListener::bind(&addr).await.expect("Failed to bind");

    println!("Listening on: {}", addr);

    let webview_connections: Arc<Mutex<Vec<tokio::sync::mpsc::UnboundedSender<String>>>> =
        Arc::new(Mutex::new(vec![]));
    let cloned_webview_connections = Arc::clone(&webview_connections);

    tokio::spawn(async move {
        let tx_for_broadcast = tx.clone();
        let mut rx = tx_for_broadcast.subscribe();

        loop {
            if let Ok(msg) = rx.recv().await {
                let connections = webview_connections.lock().await;
                for conn in connections.iter() {
                    if let Err(e) = conn.send(msg.clone()) {
                        eprintln!("Error sending to webview: {:?}", e);
                    }
                }
            }
        }
    });

    tokio::spawn(async move {
        while let Ok((stream, _)) = listener.accept().await {
            let webview_connections: Arc<Mutex<Vec<tokio::sync::mpsc::UnboundedSender<String>>>> =
                Arc::clone(&cloned_webview_connections);
            tokio::spawn(async move {
                let ws_stream = accept_async(stream)
                    .await
                    .expect("Error during the websocket handshake");
                let conn_addr = ws_stream.get_ref().peer_addr().unwrap();
                println!("New WebSocket connection: {}", conn_addr);

                let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<String>();
                {
                    let mut connections = webview_connections.lock().await;
                    connections.push(tx);
                }

                let (mut write, mut read) = ws_stream.split();

                // Handle incoming messages from webview (if needed)
                tokio::spawn(async move {
                    while let Some(msg) = read.next().await {
                        if let Ok(msg) = msg {
                            if msg.is_text() {
                                println!("Received from webview: {}", msg.to_text().unwrap());
                                // Handle incoming messages if needed
                            }
                        }
                    }
                });

                // Send messages to webview
                while let Some(msg) = rx.recv().await {
                    if write.send(Message::Text(msg)).await.is_err() {
                        break;
                    }
                }

                // When the WebSocket connection is closed, remove it from the list
                let mut connections = webview_connections.lock().await;
                connections
                    .retain(|conn: &tokio::sync::mpsc::UnboundedSender<String>| conn.is_closed());
                println!("WebSocket connection closed: {}", conn_addr);
            });
        }
    });

    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![
            core::file::start_scan_folder,
            core::file::stop_scan_folder_and_clear,
            core::file::delete_path,
            core::file::is_scanning,
            core::file::get_folder_info,
            core::file::get_folder_info_with_depth,
            core::file::get_children_by_path,
            core::file::get_node_by_path,
            core::file::get_scan_stats,
            core::file::get_performance_stats,
            core::file::get_lazy_load_config,
            core::file::fix_size_aggregations,
            core::system::get_current_os,
            core::file::get_recommend_folders,
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

fn start_watch_folder(tx: broadcast::Sender<String>) {
    // Start file watcher
    let tx_clone = tx.clone();
    tokio::spawn(async move {
        let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
            let tx = tx_clone.clone();
            match res {
                Ok(event) => {
                    let event_str = json!(event).to_string();
                    if let Err(e) = tx.send(event_str) {
                        eprintln!("Error sending file event: {:?}", e);
                    }
                    tokio::runtime::Runtime::new()
                        .unwrap()
                        .block_on(async move {
                            core::file::handle_fs_event(event).await;
                        });
                }
                Err(e) => println!("Watch error: {:?}", e),
            }
        })
        .unwrap();

        // Keep watcher running
        let mut last_watch_folders: HashSet<String> = HashSet::new();
        loop {
            // 计算应当监控的文件夹集合：当前监控路径（如果存在）
            let mut target_watch_folders = HashSet::new();
            if let Some(current_watch_path) = get_current_watch_path() {
                target_watch_folders.insert(current_watch_path.to_string_lossy().to_string());
            }

            // 当集合发生变化时更新 watcher
            if target_watch_folders != last_watch_folders {
                // 监控新增的文件夹
                for folder in target_watch_folders.difference(&last_watch_folders) {
                    println!("Watching path: {}", folder);
                    if let Err(e) = watcher.watch(Path::new(folder), RecursiveMode::NonRecursive) {
                        eprintln!("Error watching path: {:?}", e);
                    }
                }

                // 撤销已移除的文件夹监控
                for folder in last_watch_folders.difference(&target_watch_folders) {
                    println!("Unwatching path: {}", folder);
                    if let Err(e) = watcher.unwatch(Path::new(folder)) {
                        eprintln!("Error unwatching path: {:?}", e);
                    }
                }

                // 更新已监控的文件夹集合
                last_watch_folders = target_watch_folders;
            }
            tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        }
    });
}
